<!--
 * @Author: duiwei
 * @Date: 2020-11-13 17:16:18
 * @LastEditors: duiwei
 * @LastEditTime: 2020-11-18 11:51:51
 * @Description: 下拉加载，使用

    <vue-drop-down-refresh v-model="refresh" @refresh="onDropDownRefresh">
      列表组件
    </vue-drop-down-refresh>
-->

<template>
  <!-- 阻止移动端浏览器自带的下拉效果 -->
  <div
    class="pull-refresh"
    @touchstart="handlerStart"
    @touchend="handlerEnd"
    @touchmove="handlerMove"
    :style="{ height: height }"
  >
    <div class="top-refresh" :style="headStyle">
      <template v-if="isRefresh">
        <span class="iconfont icon-shuaxin"></span>加载中...
      </template>
      <template v-else-if="moveHeight > triggerRefresh">
        <span class="iconfont icon-shangla"></span>释放即可刷新...
      </template>
      <template v-else>
        <span class="iconfont icon-xiala"></span>下拉即可刷新...
      </template>
    </div>
    <div class="main-list" ref="main-list">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  name: "DropDownRefresh",
  props: {
    value: {
      type: Boolean,
      required: true
    },
    height: {
      type: String,
      default: "100vh"
    },
    bgColor: {
      type: String,
      default: "#ffffff"
    },
    color: {
      type: String,
      default: "#969799"
    }
  },
  data() {
    return {
      checkFlag: false, //判断当前是否能够触发下拉
      touchStart: 0, //初始触摸y坐标
      moveHeight: 0, //触摸移动y轴距离
      refreshHeight: 40, //显示刷新中的高度
      triggerRefresh: 60, // 触发刷新的高度
      isRefresh: false //判断是否刷新中
    };
  },
  computed: {
    headStyle() {
      return {
        height: this.moveHeight + "px",
        "background-color": this.bgColor,
        color: this.color,
        "font-size": "14px"
      };
    }
  },
  watch: {
    // 一开始只能设置false，设置true无效，设置false关闭刷新动画
    value(newValue) {
      if (!newValue) {
        this.isRefresh = newValue;
        this.moveHeight = 0;
      }
    }
  },
  methods: {
    // 触摸开始
    handlerStart(e) {
      this.checkFlag = this.checkPullStart();
      this.touchStart = e.touches[0].clientY;
    },
    // 滑动中,下拉
    handlerMove(e) {
      // 当滚动到顶部为0时触发可下拉
      if (!this.checkFlag) {
        this.handlerStart(e);
      }

      // 当刷新中不允许下拉
      if (!this.isRefresh && this.checkFlag) {
        const currentY = e.touches[0].clientY;
        let move = currentY - this.touchStart;

        // 向上滑动阻止事件传播，防止触发浏览器自带上拉刷新
        if (move > 0 && e.cancelable) {
          e.preventDefault();
        }
        this.moveHeight = this.ease(move);
      }
    },
    // 滑动结束，且当前scroll为0在顶部，触发刷新
    handlerEnd() {
      if (this.moveHeight > this.triggerRefresh && this.checkFlag) {
        // 状态刷新中，通知父组件，调整刷新中的高度
        this.isRefresh = true;
        this.moveHeight = this.refreshHeight;
        this.$emit("input", true);
        this.$emit("refresh");
      } else {
        // 没触发刷新，高度隐藏
        this.moveHeight = 0;
      }
    },
    // 拖动阻力
    ease(distance) {
      let headHeight = this.refreshHeight;

      if (distance > headHeight) {
        if (distance < headHeight * 2) {
          distance = headHeight + (distance - headHeight) / 2;
        } else {
          distance = headHeight * 1.5 + (distance - headHeight * 2) / 4;
        }
      }
      return Math.round(distance);
    },
    checkPullStart() {
      let top = this.$el.scrollTop;
      return top === 0;
    }
  }
};
</script>

<style lang="scss" scoped>
@import "./iconfont/iconfont.css";
.pull-refresh {
  display: block;
  // 触摸区域可以通过设置父组件高度
  // 父组件需要高度，这样滚动条就会出现在父组件上才能拿到scrolltop
  overflow: auto;

  .top-refresh {
    height: 0;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;

    .iconfont {
      margin-right: 6px;
    }

    @keyframes rotateIcon {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }
    .icon-shuaxin {
      animation: rotateIcon 1s linear infinite;
    }
  }

  .main-list {
    width: 100%;
  }
}
</style>
